package evl

import (
	"testing"

	"gitcode.com/deyiyangyang/bampoo/ast"
	"gitcode.com/deyiyangyang/bampoo/obj"
)

// TestDefineBasicVariable 测试基本的变量定义
func TestDefineBasicVariable(t *testing.T) {
	env := obj.NewEnvironment()
	evaluator := New(env)

	// (define x 42)
	define := &ast.DefineExpr{
		Name:  ast.Symbol{Value: "x"},
		Value: &ast.IntegerLiteral{Value: 42},
	}

	result, err := evaluator.Eval(define)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 检查返回值是nil
	if _, ok := result.(*obj.NilValue); !ok {
		t.Fatalf("expected NilValue, got %T", result)
	}

	// 检查变量是否在环境中
	val, ok := env.Get("x")
	if !ok {
		t.Fatal("expected to find x in environment")
	}

	intVal, ok := val.(*obj.IntegerValue)
	if !ok {
		t.Fatalf("expected IntegerValue, got %T", val)
	}

	if intVal.Value != 42 {
		t.Errorf("expected 42, got %d", intVal.Value)
	}
}

// TestDefineStringVariable 测试字符串变量定义
func TestDefineStringVariable(t *testing.T) {
	env := obj.NewEnvironment()
	evaluator := New(env)

	// (define name "Alice")
	define := &ast.DefineExpr{
		Name:  ast.Symbol{Value: "name"},
		Value: &ast.StringLiteral{Value: "Alice"},
	}

	_, err := evaluator.Eval(define)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	val, ok := env.Get("name")
	if !ok {
		t.Fatal("expected to find name in environment")
	}

	strVal, ok := val.(*obj.StringValue)
	if !ok {
		t.Fatalf("expected StringValue, got %T", val)
	}

	if strVal.Value != "Alice" {
		t.Errorf("expected 'Alice', got '%s'", strVal.Value)
	}
}

// TestDefineFunction 测试函数定义
func TestDefineFunction(t *testing.T) {
	env := obj.NewEnvironment()
	evaluator := New(env)

	// (define add (lambda (x y) (+ x y)))
	define := &ast.DefineExpr{
		Name: ast.Symbol{Value: "add"},
		Value: &ast.LambdaExpr{
			Parameters: []ast.Symbol{{Value: "x"}, {Value: "y"}},
			Body: []ast.Expression{
				&ast.ArithmeticExpr{
					Operator: "+",
					Operands: []ast.Expression{
						&ast.Symbol{Value: "x"},
						&ast.Symbol{Value: "y"},
					},
				},
			},
		},
	}

	_, err := evaluator.Eval(define)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 检查函数是否在环境中
	val, ok := env.Get("add")
	if !ok {
		t.Fatal("expected to find add in environment")
	}

	funcVal, ok := val.(*obj.FunctionValue)
	if !ok {
		t.Fatalf("expected FunctionValue, got %T", val)
	}

	// 检查函数参数
	if len(funcVal.Parameters) != 2 {
		t.Errorf("expected 2 parameters, got %d", len(funcVal.Parameters))
	}

	if funcVal.Parameters[0] != "x" || funcVal.Parameters[1] != "y" {
		t.Errorf("expected parameters [x y], got %v", funcVal.Parameters)
	}
}

// TestDefineComplexExpression 测试定义复杂表达式
func TestDefineComplexExpression(t *testing.T) {
	env := obj.NewEnvironment()
	evaluator := New(env)

	// (define result (+ 10 (* 5 3)))
	define := &ast.DefineExpr{
		Name: ast.Symbol{Value: "result"},
		Value: &ast.ArithmeticExpr{
			Operator: "+",
			Operands: []ast.Expression{
				&ast.IntegerLiteral{Value: 10},
				&ast.ArithmeticExpr{
					Operator: "*",
					Operands: []ast.Expression{
						&ast.IntegerLiteral{Value: 5},
						&ast.IntegerLiteral{Value: 3},
					},
				},
			},
		},
	}

	_, err := evaluator.Eval(define)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	val, ok := env.Get("result")
	if !ok {
		t.Fatal("expected to find result in environment")
	}

	intVal, ok := val.(*obj.IntegerValue)
	if !ok {
		t.Fatalf("expected IntegerValue, got %T", val)
	}

	if intVal.Value != 25 { // 10 + (5 * 3) = 25
		t.Errorf("expected 25, got %d", intVal.Value)
	}
}

// TestDefineOverwrite 测试变量覆盖
func TestDefineOverwrite(t *testing.T) {
	env := obj.NewEnvironment()
	evaluator := New(env)

	// 第一次定义 (define x 10)
	define1 := &ast.DefineExpr{
		Name:  ast.Symbol{Value: "x"},
		Value: &ast.IntegerLiteral{Value: 10},
	}

	_, err := evaluator.Eval(define1)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 第二次定义 (define x 20)
	define2 := &ast.DefineExpr{
		Name:  ast.Symbol{Value: "x"},
		Value: &ast.IntegerLiteral{Value: 20},
	}

	_, err = evaluator.Eval(define2)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	val, ok := env.Get("x")
	if !ok {
		t.Fatal("expected to find x in environment")
	}

	intVal, ok := val.(*obj.IntegerValue)
	if !ok {
		t.Fatalf("expected IntegerValue, got %T", val)
	}

	if intVal.Value != 20 {
		t.Errorf("expected 20 (overwritten), got %d", intVal.Value)
	}
}

// TestDefineInNestedScope 测试嵌套作用域中的定义
func TestDefineInNestedScope(t *testing.T) {
	env := obj.NewEnvironment()
	evaluator := New(env)

	// 在外部作用域定义 (define outer 100)
	defineOuter := &ast.DefineExpr{
		Name:  ast.Symbol{Value: "outer"},
		Value: &ast.IntegerLiteral{Value: 100},
	}

	_, err := evaluator.Eval(defineOuter)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 定义一个函数，内部定义同名变量 (define (test) (define outer 200) outer)
	defineFunc := &ast.DefineExpr{
		Name: ast.Symbol{Value: "test"},
		Value: &ast.LambdaExpr{
			Parameters: []ast.Symbol{},
			Body: []ast.Expression{
				&ast.DefineExpr{
					Name:  ast.Symbol{Value: "outer"},
					Value: &ast.IntegerLiteral{Value: 200},
				},
				&ast.Symbol{Value: "outer"},
			},
		},
	}

	_, err = evaluator.Eval(defineFunc)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// 调用函数应该返回内部定义的200
	call := &ast.List{
		Elements: []ast.Expression{
			&ast.Symbol{Value: "test"},
		},
	}

	result, err := evaluator.Eval(call)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	intVal, ok := result.(*obj.IntegerValue)
	if !ok {
		t.Fatalf("expected IntegerValue, got %T", result)
	}

	if intVal.Value != 200 {
		t.Errorf("expected 200 (inner scope), got %d", intVal.Value)
	}

	// 外部作用域的值应该保持不变
	outerVal, ok := env.Get("outer")
	if !ok {
		t.Fatal("expected to find outer in environment")
	}

	outerIntVal, ok := outerVal.(*obj.IntegerValue)
	if !ok {
		t.Fatalf("expected IntegerValue, got %T", outerVal)
	}

	if outerIntVal.Value != 100 {
		t.Errorf("expected outer scope to remain 100, got %d", outerIntVal.Value)
	}
}
